package cn.snmp.mutual.org.bouncycastle.crypto.digests;

public class SHA1Digest extends GeneralDigest {
    private static final int DIGEST_LENGTH = 20;
    private int H1;
    private int H2;
    private int H3;
    private int H4;
    private int H5;
    private int[] X;
    private int xOff;
    private static final int Y1 = 1518500249;
    private static final int Y2 = 1859775393;
    private static final int Y3 = -1894007588;
    private static final int Y4 = -899497514;

    public SHA1Digest() {
        this.X = new int[80];
        this.reset();
    }

    public SHA1Digest(final SHA1Digest t) {
        super(t);
        this.X = new int[80];
        this.H1 = t.H1;
        this.H2 = t.H2;
        this.H3 = t.H3;
        this.H4 = t.H4;
        this.H5 = t.H5;
        System.arraycopy(t.X, 0, this.X, 0, t.X.length);
        this.xOff = t.xOff;
    }

    public String getAlgorithmName() {
        return "SHA-1";
    }

    public int getDigestSize() {
        return 20;
    }

    @Override
    protected void processWord(final byte[] in, final int inOff) {
        this.X[this.xOff++] = ((in[inOff] & 0xFF) << 24 | (in[inOff + 1] & 0xFF) << 16 | (in[inOff + 2] & 0xFF) << 8 | (in[inOff + 3] & 0xFF));
        if (this.xOff == 16) {
            this.processBlock();
        }
    }

    private void unpackWord(final int word, final byte[] out, final int outOff) {
        out[outOff] = (byte) (word >>> 24);
        out[outOff + 1] = (byte) (word >>> 16);
        out[outOff + 2] = (byte) (word >>> 8);
        out[outOff + 3] = (byte) word;
    }

    @Override
    protected void processLength(final long bitLength) {
        if (this.xOff > 14) {
            this.processBlock();
        }
        this.X[14] = (int) (bitLength >>> 32);
        this.X[15] = (int) (bitLength & -1L);
    }

    public int doFinal(final byte[] out, final int outOff) {
        this.finish();
        this.unpackWord(this.H1, out, outOff);
        this.unpackWord(this.H2, out, outOff + 4);
        this.unpackWord(this.H3, out, outOff + 8);
        this.unpackWord(this.H4, out, outOff + 12);
        this.unpackWord(this.H5, out, outOff + 16);
        this.reset();
        return 20;
    }

    @Override
    public void reset() {
        super.reset();
        this.H1 = 1732584193;
        this.H2 = -271733879;
        this.H3 = -1732584194;
        this.H4 = 271733878;
        this.H5 = -1009589776;
        this.xOff = 0;
        for (int i = 0; i != this.X.length; ++i) {
            this.X[i] = 0;
        }
    }

    private int f(final int u, final int v, final int w) {
        return (u & v) | (~u & w);
    }

    private int h(final int u, final int v, final int w) {
        return u ^ v ^ w;
    }

    private int g(final int u, final int v, final int w) {
        return (u & v) | (u & w) | (v & w);
    }

    private int rotateLeft(final int x, final int n) {
        return x << n | x >>> 32 - n;
    }

    @Override
    protected void processBlock() {
        for (int i = 16; i <= 79; ++i) {
            this.X[i] = this.rotateLeft(this.X[i - 3] ^ this.X[i - 8] ^ this.X[i - 14] ^ this.X[i - 16], 1);
        }
        int A = this.H1;
        int B = this.H2;
        int C = this.H3;
        int D = this.H4;
        int E = this.H5;
        for (int j = 0; j <= 19; ++j) {
            final int t = this.rotateLeft(A, 5) + this.f(B, C, D) + E + this.X[j] + 1518500249;
            E = D;
            D = C;
            C = this.rotateLeft(B, 30);
            B = A;
            A = t;
        }
        for (int j = 20; j <= 39; ++j) {
            final int t = this.rotateLeft(A, 5) + this.h(B, C, D) + E + this.X[j] + 1859775393;
            E = D;
            D = C;
            C = this.rotateLeft(B, 30);
            B = A;
            A = t;
        }
        for (int j = 40; j <= 59; ++j) {
            final int t = this.rotateLeft(A, 5) + this.g(B, C, D) + E + this.X[j] - 1894007588;
            E = D;
            D = C;
            C = this.rotateLeft(B, 30);
            B = A;
            A = t;
        }
        for (int j = 60; j <= 79; ++j) {
            final int t = this.rotateLeft(A, 5) + this.h(B, C, D) + E + this.X[j] - 899497514;
            E = D;
            D = C;
            C = this.rotateLeft(B, 30);
            B = A;
            A = t;
        }
        this.H1 += A;
        this.H2 += B;
        this.H3 += C;
        this.H4 += D;
        this.H5 += E;
        this.xOff = 0;
        for (int k = 0; k != this.X.length; ++k) {
            this.X[k] = 0;
        }
    }
}
